/**
 * 深拷贝
 * @param {*} obj
 * @param {*} res
 * @returns
 */
export function deepClone(obj, cache = []) {
  // 如果obj是基础类型数据，则直接返回其副本
  if (typeof obj !== "object" || obj === null) {
    return obj;
  }

  // 获取obj的构造函数类型
  const typeStr = Object.prototype.toString.call(obj);

  // 对Date、RegExp、Error对象做特殊处理
  if (typeStr === "[object RegExp]" || typeStr === "[object Date]") {
    const copyObj = new obj.constructor();
    copyObj.source = obj.source;
    copyObj.flags = obj.flags;
    copyObj.lastIndex = obj.lastIndex;
    copyObj.locale = obj.locale;
    return copyObj;
  } else if (typeStr === "[object Error]") {
    const copyObj = new obj.constructor();
    copyObj.message = obj.message;
    copyObj.name = obj.name;
    if ("stack" in obj) {
      // 不同浏览器对Error.stack有不同的实现，有的浏览器会报错
      copyObj.stack = obj.stack;
    }
    return copyObj;
  }

  // 对于数组的情况，递归复制每一项元素
  if (Array.isArray(obj)) {
    const copyObj = [];
    for (let i = 0; i < obj.length; i++) {
      copyObj[i] = deepClone(obj[i], cache);
    }
    return copyObj;
  }

  // 对于对象的情况，递归复制每一个属性
  const copyObj = {};
  for (let key in obj) {
    if (Reflect.has(obj, key)) {
      copyObj[key] = deepClone(obj[key], cache);
    }
  }
  return copyObj;
}

/**
 * 指定范围内的随机整数
 * @param {Number} minimum
 * @param {Number} maximum
 * @returns
 */
export const randomNum = (minimum, maximum) => {
  var number = Math.floor(minimum + Math.random() * (maximum - minimum));
  return number;
};

/**
 * 数字超过99显示99+
 * @param { Number } num
 * @param { String } str 后缀可自定义
 * @returns
 */
export const numFilter = (num, str = "+") => {
  if (Object.prototype.toString.call(str).slice(8, -1) !== "String") {
    console.warn("第二参数为最好为字符串类型!");
  }
  num = num ? num - 0 : 0;
  if (num > 99) {
    return "99" + str;
  } else {
    return num;
  }
};

/**
 * 计算函数执行所用时间 带参数
 * @param {*} func
 * @param {*} args
 * @returns
 */
export function computeTime(func, ...args) {
  const start = performance.now();
  func(...args);
  const end = performance.now();

  console.log(`Function took ${end - start} milliseconds to execute.`);
  return end - start;
}

/**
 * 判断是android还是ios还是web
 * @returns
 */
export const isDevice = () => {
  var ua = navigator.userAgent.toLowerCase();
  if (ua.match(/iPhone\sOS/i) === "iphone os" || ua.match(/iPad/i) === "ipad") {
    // ios
    return "iOS";
  }
  if (ua.match(/Android/i) === "android") {
    return "Android";
  }
  return "Web";
};

/**
 * 判断是否为微信
 * @returns
 */
export const isWx = () => {
  var ua = window.navigator.userAgent.toLowerCase();
  if (ua.match(/MicroMessenger/i) === "micromessenger") {
    return true;
  }
  return false;
};

/**
 * 判断图片加载完成
 * @param {Array} arr
 * @param {Function} callback
 */
export const imgLoadAll = function (arr, callback) {
  let arrImg = [];
  for (let i = 0; i < arr.length; i++) {
    let img = new Image();
    img.src = arr[i];
    img.onload = function () {
      arrImg.push(this);
      if (arrImg.length == arr.length) {
        callback && callback();
      }
    };
  }
};

/**
 * 复制文本
 * @param {String} text
 * @param {Function} fn
 * @returns
 */
export const copyTxt = function (text, fn) {
  // 复制功能
  if (typeof document.execCommand !== "function") {
    console.log("复制失败，请长按复制");
    return;
  }
  var dom = document.createElement("textarea");
  dom.value = text;
  dom.setAttribute("style", "display: block;width: 1px;height: 1px;");
  document.body.appendChild(dom);
  dom.select();
  var result = document.execCommand("copy");
  document.body.removeChild(dom);
  if (result) {
    console.log("复制成功");
    typeof fn === "function" && fn();
    return;
  }
  if (typeof document.createRange !== "function") {
    console.log("复制失败，请长按复制");
    return;
  }
  var range = document.createRange();
  var div = document.createElement("div");
  div.innerhtml = text;
  div.setAttribute("style", "height: 1px;fontSize: 1px;overflow: hidden;");
  document.body.appendChild(div);
  range.selectNode(div);
  var selection = window.getSelection();
  console.log(selection);
  if (selection.rangeCount > 0) {
    selection.removeAllRanges();
  }
  selection.addRange(range);
  document.execCommand("copy");
  typeof fn === "function" && fn();
  console.log("复制成功");
};

/**
 * base64图片下载
 * @param {*} base64
 * @param {*} fileName
 */
export const downloadBaseFile = function (base64, fileName) {
  //base64图片下载功能
  let base64ToBlob = function (code) {
    let parts = code.split(";base64,");
    let contentType = parts[0].split(":")[1];
    let raw = window.atob(parts[1]);
    let rawLength = raw.length;
    let uInt8Array = new Uint8Array(rawLength);
    for (let i = 0; i < rawLength; ++i) {
      uInt8Array[i] = raw.charCodeAt(i);
    }
    return new Blob([uInt8Array], {
      type: contentType,
    });
  };
  let aLink = document.createElement("a");
  let blob = base64ToBlob(base64); //new Blob([content]);
  let evt = document.createEvent("HTMLEvents");
  evt.initEvent("click", true, true); //initEvent不加后两个参数在FF下会报错  事件类型，是否冒泡，是否阻止浏览器的默认行为
  aLink.download = fileName;
  aLink.href = URL.createObjectURL(blob);
  aLink.click();
};

/**
 * 防抖
 * @param {*} func
 * @param {*} wait
 * @param {*} immediate
 * @returns
 */
export const debounce = function (func, wait, immediate) {
  //函数防抖[func 函数,wait 延迟执行毫秒数,immediate true 表立即执行,false 表非立即执行,立即执行是触发事件后函数会立即执行，然后n秒内不触发事件才能继续执行函数的效果]
  let timeout;
  return function () {
    let context = this;
    let args = arguments;
    if (timeout) clearTimeout(timeout);
    if (immediate) {
      var callNow = !timeout;
      timeout = setTimeout(() => {
        timeout = null;
      }, wait);
      if (callNow) func.apply(context, args);
    } else {
      timeout = setTimeout(function () {
        func.apply(context, args);
      }, wait);
    }
  };
};

/**
 * 节流
 * @param {*} func
 * @param {*} delay
 */
export const throttle = (func, delay) => {
  let lastCall = 0;
  return function () {
    const now = Date.now();
    if (now - lastCall > delay) {
      func.apply(this, arguments);
      lastCall = now;
    }
  };
};
